package model.handler.emailHandling;

import java.io.File;
import java.util.Properties;

import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.activation.FileDataSource;
import javax.mail.BodyPart;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

/**
 * Utility class for sending emails.
 *
 */
public final class EmailHandler {
	
	private final static Logger log = LogManager.getLogger("ERROR");
	private static Logger debug = LogManager.getLogger("DEBUG");

	private EmailHandler() {
		throw new AssertionError("Utiltiy class musn't be instantiated.");
	}

	/**
	 * Sends an email containing the monthly invoice of a customer.
	 * @param bccMail
	 * @param operatorName
	 * @param recipientName
	 * @param recipientAddress
	 * @param password
	 * @param username
	 * @param date
	 * @param file
	 * @return
	 */
	public static boolean sendInvoiceMail(String bccMail, String operatorName, String recipientName, String recipientAddress, String password,
			String username, String date, File file) {

		try {
			// Create a default MimeMessage object.
			MimeMessage message = createDefaultMail(username, password, bccMail, recipientAddress);

			// Set Subject: header field
			message.setSubject("Ihre Getränkerechnung von " + date);

			// Create the message part
			BodyPart messageBodyPart = new MimeBodyPart();

			// Fill the message
			messageBodyPart.setText(createStandardInvoiceMailText(operatorName, recipientName, date));

			// Create a multipart message
			Multipart multipart = new MimeMultipart();

			// Set text message part
			multipart.addBodyPart(messageBodyPart);
			
			// Part two is attachment
			messageBodyPart = new MimeBodyPart();

			multipart.addBodyPart(appendFileToMessage(file, "Getränkerechnung_" + date + ".pdf"));
			// Send the complete message parts
			message.setContent(multipart);
			
			// Send message
			Transport.send(message);
			file.deleteOnExit();
			debug.debug("Customer invoice mail successfully sent to: " + recipientName + "(" + recipientAddress + ")");
		} catch (MessagingException mex) {
			mex.printStackTrace();
			log.error(mex.getMessage());
		}
		return true;
	}

	/**
	 * Sends an email containing the balance invoice and the salary invoice to the "Haussprecher";
	 * @param username
	 * @param password
	 * @param recipientMail
	 * @param balanceInvoice
	 * @param salaryInvoice
	 * @param date
	 */
	public static void sendBalanceMail(String username, String password, String recipientMail, File balanceInvoice, File salaryInvoice, String date) {

		try {
			// Create a default MimeMessage object.
			MimeMessage message = createDefaultMail(username, password,null, recipientMail);

			// Set Subject: header field
			message.setSubject("Abrechnung Getränkeverkauf " + date);

			// Create the message part
			BodyPart messageBodyPart = new MimeBodyPart();

			// Fill the message
			messageBodyPart.setText("Servus Haussprecher,\n\nanbei erhältst du die Abrechnungen des Getränkeladens vom letzten Monat.");

			// Create a multipart message
			Multipart multipart = new MimeMultipart();

			// Set text message part
			multipart.addBodyPart(messageBodyPart);
			
			// Part two is attachment
			messageBodyPart = new MimeBodyPart();

			multipart.addBodyPart(appendFileToMessage(balanceInvoice, "Monatsbilanz_" + date + ".pdf"));
			multipart.addBodyPart(appendFileToMessage(salaryInvoice, "Lohnkostenabrechnung_" + date + ".pdf"));
			// Send the complete message parts
			message.setContent(multipart);
			
			// Send message
			Transport.send(message);
			
			balanceInvoice.deleteOnExit();
			salaryInvoice.deleteOnExit();
			
			debug.debug("Email containing the balance invoices was sent to: " + recipientMail);
		} catch (MessagingException mex) {
			mex.printStackTrace();
			log.error(mex.getMessage());
		}
	}
	
	/**
	 * Helper method returning the standard text for the monthly customer invoice.
	 * @param operatorName
	 * @param recipientName
	 * @param date
	 * @return
	 */
	private static String createStandardInvoiceMailText(String operatorName, String recipientName, String date) {
		StringBuilder sb = new StringBuilder();
		sb.append("Hallo ");
		sb.append(recipientName);
		sb.append(",\n\nals Anlage erhalten Sie Ihre Rechnung vom Hausladen des Blauen Hauses (Haus 11) in der Studentenstadt Freimann\nfür die Abrechnungsperiode ");
		sb.append(date);
		sb.append(".\nBitte beachten Sie, dass diese Rechnung bis Ende des Monats zu begleichen ist.");
		sb.append("\n\nMit freundlichen Grüßen\n");
		sb.append(operatorName);
		sb.append("\n\n=================================================\n"
				+ "ACHTUNG DIES IST EINE AUTOMATISCH GENERIERTE EMAIL\n\n"
				+ "Bitte überprüfen Sie die Rechnung auf Richtigkeit,\n"
				+ "sollten Zweifel an der Korrektheit bestehen,\n"
				+ "bitte ich Sie auf diese E-Mail mit Angabe einer Begründung zu antworten.");

		return sb.toString();
	}

	/**
	 * Sets up the parameter for sending an email.
	 * The "Haussprecher" ist set as recipient on BCC.
	 * @param username
	 * @param password
	 * @param bccMail
	 * @param recipientAddress
	 * @return
	 */
	private static MimeMessage createDefaultMail(String username, String password, String bccMail, String recipientAddress) {
		// Sender's email ID needs to be mentioned
		String from = "gvblaueshaus@stusta.de";

		// Create a default MimeMessage object.
		MimeMessage message = new MimeMessage(getSession(username, password));

		// Set From: header field of the header.
		try {
			message.setFrom(new InternetAddress(from));
			// Set To: header field of the header.
			message.addRecipient(Message.RecipientType.TO, new InternetAddress(recipientAddress));

			if (bccMail != null) {
				message.addRecipient(Message.RecipientType.BCC, new InternetAddress(bccMail));
			}
		} catch (AddressException e) {
			e.printStackTrace();
			log.error(e.getMessage());
		} catch (MessagingException e) {
			e.printStackTrace();
			log.error(e.getMessage());
		}

		return message;
	}
	
	/**
	 * Returns a session for sending emails.
	 * @param username
	 * @param password
	 * @return
	 */
	private static Session getSession(String username, String password) {
		String host = "mail.stusta.mhn.de";

		// Get system properties
		Properties props = System.getProperties();

		// Setup mail server
		props.setProperty("mail.stusta.mhn.de ", host);

		props.put("mail.smtp.auth", "true");
		props.put("mail.smtp.starttls.enable", "true");
		props.put("mail.smtp.host", host);
		props.put("mail.smtp.port", "587");

		// Get the default Session object.
		Session session = Session.getInstance(props, new javax.mail.Authenticator() {

			@Override
			protected PasswordAuthentication getPasswordAuthentication() {
				return new PasswordAuthentication(username, password);
			}
		});

		return session;
	}

	/**
	 * Appends a given file to a message.
	 * @param file
	 * @param fileName
	 * @return
	 */
	private static BodyPart appendFileToMessage(File file, String fileName) {
		BodyPart messageBodyPart = new MimeBodyPart();
		try {
			DataSource source = new FileDataSource(file);
			messageBodyPart.setDataHandler(new DataHandler(source));
			messageBodyPart.setFileName(fileName);
			debug.debug(fileName + " File appended");

		} catch (MessagingException e) {
			e.printStackTrace();
			log.error(e.getMessage());
		}
		return messageBodyPart;
	}
}
